//
//  NSObject+Binding.m
//  LAMapBasicDemo
//
//  Created by 罗亮富 on 2018/1/8.
//  Copyright © 2018年 2Bulu. All rights reserved.
//

#import "NSObject+Binding.h"
#import <objc/runtime.h>
#import "WeakReference.h"


static char dic__Key;
@implementation NSObject (Binding)

-(void)bindObject:(nonnull id)obj forKey:(nonnull NSString *)key policy:(ObjectBindPolicy)policy
{
    NSMutableDictionary *dic = objc_getAssociatedObject(self, &dic__Key);
    if(!dic)
    {
        dic = [NSMutableDictionary dictionaryWithCapacity:3];
        objc_setAssociatedObject(self, &dic__Key, dic, OBJC_ASSOCIATION_RETAIN);
    }
    else if(dic.count > 5)
    {
        [self removeRedundantWeakContainerObjects:dic];
    }
    @synchronized(dic)
    {
        if(policy == ObjectBindCopy)
            [dic setObject:[obj copy] forKey:key];
        else if(policy == ObjectBindStrong)
            [dic setObject:obj forKey:key];
        else
        {
            WeakReference *instance = [WeakReference instanceWithRefrenceObject:obj];
            [dic setObject:instance forKey:key];
        }
    }
}


-(nullable id)bindedObjectForKey:(nonnull NSString *)key
{
    NSMutableDictionary *dic = objc_getAssociatedObject(self, &dic__Key);
    if(!dic)
        return nil;
    
    @synchronized(dic)
    {
        id retObj = [dic objectForKey:key];
        if([retObj isKindOfClass:[WeakReference class]])
        {
            WeakReference *fObj = retObj;
            retObj = fObj.weakObj;
            if(fObj && !retObj)
            {
                [dic removeObjectForKey:key];
            }
        }
        return retObj;
    }
}

-(void)removeBindedObjectForKey:(NSString *)key
{
    NSMutableDictionary *dic = objc_getAssociatedObject(self, &dic__Key);
    @synchronized(dic)
    {
        [dic removeObjectForKey:key];
    }
}

-(void)removeAllBindedObjects
{
    NSMutableDictionary *dic = objc_getAssociatedObject(self, &dic__Key);
    @synchronized(dic)
    {
        [dic removeAllObjects];
    }
}

-(void)enumerateBindedKeysAndObjectsUsingBlock:(void ( ^)(NSString *key, id obj, BOOL *stop))block
{
    NSMutableDictionary *dic = objc_getAssociatedObject(self, &dic__Key);
    NSMutableArray *rmks = [NSMutableArray arrayWithCapacity:dic.count];
    
    NSMutableDictionary *dicCopy = [dic copy];
    [dicCopy enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        
        id passObj = obj;
        if([obj isKindOfClass:[WeakReference class]])
        {
            WeakReference *fObj = obj;
            passObj = fObj.weakObj;
            if(!passObj)
            {
                [rmks addObject:key];
            }
        }
        
        if(passObj)
            block(key,passObj,stop);
    }];
 
    if(rmks.count > 0)
    {
        @synchronized(dic)
        {
            [dic removeObjectsForKeys:rmks];
        }
    }
}


-(void)removeRedundantWeakContainerObjects:(NSMutableDictionary *)dic
{
    if(dic)
    {
        NSMutableArray *mAry = [NSMutableArray arrayWithCapacity:dic.count];
        @synchronized(dic)
        {
            [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

                if([obj isKindOfClass:[WeakReference class]])
                {
                    WeakReference *fObj = obj;
                    if(!fObj.weakObj)
                        [mAry addObject:key];
                }
            }];

            [dic removeObjectsForKeys:mAry];
        }
    }
}

@end
